package local

import (
	"errors"
	"fmt"
	"github.com/labstack/gommon/log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

// LocalOss 自定义上传
type LocalOss struct {
	Bucket     *oss.Bucket
	bucketName string
	endPoint   string
}

// InitLocalOss 初始化 OSS。
func InitLocalOss(bucketName string, endPoint string, keyID string, keySecret string) (*LocalOss, error) {
	var (
		localOss = LocalOss{bucketName: bucketName, endPoint: endPoint}
		client   *oss.Client
		err      error
	)
	client, err = oss.New(endPoint, keyID, keySecret)
	if err != nil {
		log.Error("-- InitLocalOss client Error: ", bucketName, " ", err.Error())
		return &localOss, err
	}
	localOss.Bucket, err = client.Bucket(bucketName)
	if err != nil {
		log.Error("-- InitLocalOss bucket Error: ", bucketName, " ", err.Error())
		return &localOss, err
	}
	log.Info("-- InitLocalOss success. bucketName", bucketName, ".")
	return &localOss, err
}

// IsObjectExist 判断 oss 中文件是否已存在。
func (localOss *LocalOss) IsObjectExist(fPath string) bool {
	isExist, err := localOss.Bucket.IsObjectExist(fPath)
	if err != nil {
		log.Error("-- LocalOss IsObjectExist ", fPath, " Error: ", err.Error())
		return false
	}
	return isExist
}

// GetBucketPutUrl 获取上传 URL 上传图片。()(PutURL, contentType)
func (localOss *LocalOss) GetPutURL(fPath string) (string, string) {
	// 判断是否支持文件。
	contentType := GetContentType(fPath)
	if contentType == "" {
		return "", ""
	}
	options := []oss.Option{
		oss.ContentType(contentType),
	}
	putURL, err := localOss.Bucket.SignURL(fPath, oss.HTTPPut, 60*60, options...)
	if err != nil {
		log.Error("-- LocalOss GetPutUrl ", fPath, " Error: ", err.Error())
	}
	return putURL, contentType
}

// GetHttpsUrl 获取私有访问 URL。
func (localOss *LocalOss) GetHttpsURL(fPath string) string {
	var (
		URL string
		err error
	)
	if fPath != "" {
		URL, err = localOss.Bucket.SignURL(fPath, oss.HTTPGet, 60*60*24)
		if err != nil {
			log.Error("-- LocalOss GetHttpsUrl ", fPath, " Error: ", err.Error())
		}
		len := len(URL) // 替换 http 为 https 。
		if len > 4 {
			URL = "https" + URL[4:]
		}
	}
	return URL
}

// GetHttpsUrl 获取公共读的 URL。(bucket 是公共读的才可以)
func (localOss *LocalOss) GetPublicURL(fPath string) string {
	var URL string
	if fPath != "" {
		URL = fmt.Sprintf("https://%s.%s/%s", localOss.bucketName, localOss.endPoint, fPath)
	}
	return URL
}

// GetImgURL 获取图片临时下载链接。
func (localOss *LocalOss) GetImgURL(fPath string) string {
	var (
		URL string
		err error
	)
	URL, err = localOss.Bucket.SignURL(fPath, oss.HTTPGet, 60*60*2, oss.Process("image/format,png"))
	if err != nil {
		log.Error("-- GetImgURL ", fPath, " Error: ", err.Error())
	}
	return URL
}

// DelFile 直接删除文件。
func (localOss *LocalOss) DelFile(fPath string) error {
	// 判断文件是否存在。
	if isExist := localOss.IsObjectExist(fPath); !isExist {
		log.Error("-- LocalOss DelFile file no exist ", fPath)
		return errors.New("文件不在。")
	}

	// 删除 oss 里的文件
	err := localOss.Bucket.DeleteObject(fPath)
	if err != nil {
		log.Error("-- LocalOss DelFile ", fPath, " Error: ", err.Error())
		return err
	}
	return err
}

/* ------ 相关函数 ------ */

// ContentType 支持的文件类型。
var ContentType map[string]string = map[string]string{
	".jpe":  "image/jpeg",
	".jpeg": "image/jpeg",
	".jpg":  "image/jpeg",
	".png":  "image/png",
	".mp3":  "audio/mp3",
	".wav":  "audio/wav",
}

// GetContentType 获取支持文件类型的 ContentType
func GetContentType(fPath string) string {
	// contentType := "application/octet-stream"
	contentType := ""
	strArr := strings.Split(fPath, ".")
	fType := "."
	if len(strArr) > 0 {
		fType = "." + strArr[len(strArr)-1]
	}
	if value, ok := ContentType[fType]; ok {
		contentType = value
	}
	return contentType
}

// GetFileSize 获取本地文件大小。
func GetFileSize(filename string) string {
	var result float32
	filepath.Walk(filename, func(path string, f os.FileInfo, err error) error {
		result = float32(f.Size())
		return nil
	})
	return strconv.FormatFloat(float64(result/1000), 'f', 1, 64)
}
